package org.tacademy.basic.sampletabfragment;

import java.util.ArrayList;
import java.util.HashMap;

import android.content.Context;
import android.os.Bundle;
import android.support.v4.app.Fragment;
import android.support.v4.app.FragmentActivity;
import android.support.v4.app.FragmentTransaction;
import android.view.View;
import android.widget.TabHost;
import android.widget.TabHost.OnTabChangeListener;

public class TabManager implements OnTabChangeListener {

    private final FragmentActivity mActivity;
    private final TabHost mTabHost;
    private final int mContainerId;
    private final HashMap<String, TabInfo> mTabs = new HashMap<String, TabInfo>();
    TabInfo mLastTab;

    static final class TabInfo {
        private final String tag;
        private final Class<?> clss;
        private final Bundle args;
        private Fragment fragment;
        private Fragment firstFragment;
        private boolean bShowFirstFragmentWhenTabSelect = true;
        private boolean bBackStackEnable = false;
        private ArrayList<Fragment> mFragmentStack = new ArrayList<Fragment>();
        

        TabInfo(String _tag, Class<?> _class, Bundle _args, boolean bShowFirst) {
            tag = _tag;
            clss = _class;
            args = _args;
            bShowFirstFragmentWhenTabSelect = bShowFirst;
        }
    }

    static class DummyTabFactory implements TabHost.TabContentFactory {
        private final Context mContext;

        public DummyTabFactory(Context context) {
            mContext = context;
        }

        @Override
        public View createTabContent(String tag) {
            View v = new View(mContext);
            v.setMinimumWidth(0);
            v.setMinimumHeight(0);
            return v;
        }
    }

    public TabManager(FragmentActivity activity, TabHost tabHost, int containerId) {
        mActivity = activity;
        mTabHost = tabHost;
        mContainerId = containerId;
        mTabHost.setOnTabChangedListener(this);
    }

    public void addTab(TabHost.TabSpec tabSpec, Class<?> clss, Bundle args) {
    	addTab(tabSpec,clss,args,true);
    }
    
    public void addTab(TabHost.TabSpec tabSpec, Class<?> clss, Bundle args, boolean isShowFirstFragmentWhenTabSelected) {
        tabSpec.setContent(new DummyTabFactory(mActivity));
        String tag = tabSpec.getTag();

        TabInfo info = new TabInfo(tag, clss, args,isShowFirstFragmentWhenTabSelected);

        // Check to see if we already have a fragment for this tab, probably
        // from a previously saved state.  If so, deactivate it, because our
        // initial state is that a tab isn't shown.
        info.firstFragment = mActivity.getSupportFragmentManager().findFragmentByTag(tag);
        info.fragment = info.firstFragment;
        if (info.fragment != null && !info.fragment.isDetached()) {
            FragmentTransaction ft = mActivity.getSupportFragmentManager().beginTransaction();
            ft.detach(info.fragment);
            ft.commit();
        }

        mTabs.put(tag, info);
        mTabHost.addTab(tabSpec);
    }

    public void addFragmentAtCurrentTab(Fragment f) {
    	if (mLastTab != null) {
    		if (mLastTab.fragment != null) {
    			FragmentTransaction ft = mActivity.getSupportFragmentManager().beginTransaction();
    			
    			clearTabFragment(mLastTab,ft);
    			
		    	mLastTab.fragment = f;
		    	ft.add(mContainerId, f);
		    	ft.commit();
    		}
    	}
    }
    
    public void addFragmentStackAtCurrentTab(Fragment f) {
    	if (mLastTab != null) {
    		if (mLastTab.fragment != null) {
    			FragmentTransaction ft = mActivity.getSupportFragmentManager().beginTransaction();
    			
    			int size = mLastTab.mFragmentStack.size();
    			if (size > 0) {
    				Fragment topFragment = mLastTab.mFragmentStack.get(size - 1);
    				ft.detach(topFragment);
    			} else {
    				ft.detach(mLastTab.fragment);
    			}
    			
    			mLastTab.mFragmentStack.add(f);
    			ft.add(mContainerId, f);
    			ft.commit();
    		}
    	}
    }
    
    private boolean clearTabStackFragment(TabInfo tabInfo, FragmentTransaction ft) {
		if (tabInfo.mFragmentStack.size() > 0) {
			for (int i = tabInfo.mFragmentStack.size() - 1; i >=0 ; i--) {
				Fragment sf = tabInfo.mFragmentStack.get(i);
				ft.remove(sf);
			}
			tabInfo.mFragmentStack.clear();
			return true;
		}
		return false;
    }
    
    private void clearTabFragment(TabInfo tabInfo, FragmentTransaction ft) {
		clearTabStackFragment(tabInfo,ft);
    	if (tabInfo.fragment == tabInfo.firstFragment) {
    		ft.detach(tabInfo.fragment);
    	} else {
    		ft.remove(tabInfo.fragment);
    	}    	
    }
    
    public void moveFirstFragmentAtCurrentTab() {
    	if (mLastTab != null) {
    		if (mLastTab.fragment != null) {
				FragmentTransaction ft = mActivity.getSupportFragmentManager().beginTransaction();
				boolean isStackExist = clearTabStackFragment(mLastTab, ft);
    			if (mLastTab.fragment != mLastTab.firstFragment) {
    				ft.remove(mLastTab.fragment);
    				mLastTab.fragment = mLastTab.firstFragment;
    				ft.attach(mLastTab.fragment);
    			} else if (isStackExist) {
    				ft.attach(mLastTab.fragment);
    			}    			
				ft.commit();
    		}
    	}
    }
    
    public boolean backStackFragmentAtCurrentTab() {
    	if (mLastTab != null) {
    		if (mLastTab.fragment != null) {
    			int size = mLastTab.mFragmentStack.size();
    			if ( size > 0) {
        			FragmentTransaction ft = mActivity.getSupportFragmentManager().beginTransaction();
    				Fragment oFragment = mLastTab.mFragmentStack.remove(size - 1);
    				Fragment nFragment = (size > 1) ? mLastTab.mFragmentStack.get(size - 2) : mLastTab.fragment;
    				ft.remove(oFragment);
    				ft.attach(nFragment);
    				ft.commit();
    				return true;
    			} 
    		}
    	}
    	return false;
    }
    
    private void setTabFragment(TabInfo tabInfo, FragmentTransaction ft) {
    	Fragment f;
    	if (tabInfo.mFragmentStack.size() > 0) {
    		f = tabInfo.mFragmentStack.get(tabInfo.mFragmentStack.size() - 1);
    	} else {
    		f = tabInfo.fragment;
    	}
    	
    	ft.attach(f);
    }
    
    public boolean backPressed() {
    	boolean isBackProcessed = false;
    	if (mLastTab != null) {
    		TabFragment f;
    		if (mLastTab.mFragmentStack.size() > 0) {
    			f = (TabFragment)mLastTab.mFragmentStack.get(mLastTab.mFragmentStack.size() - 1);
    		} else {
    			f = (TabFragment)mLastTab.fragment;
    		}
    		isBackProcessed = f.onBackPressed();
    	}
    	return isBackProcessed;
    }
    
    @Override
    public void onTabChanged(String tabId) {
        TabInfo newTab = mTabs.get(tabId);
        if (mLastTab != newTab) {
            FragmentTransaction ft = mActivity.getSupportFragmentManager().beginTransaction();
            if (mLastTab != null) {
                if (mLastTab.fragment != null) {
                	if (mLastTab.bShowFirstFragmentWhenTabSelect) {
                		clearTabStackFragment(mLastTab,ft);
                    	if (mLastTab.fragment == mLastTab.firstFragment) {
                    		ft.detach(mLastTab.fragment);
                    	} else {
                    		ft.remove(mLastTab.fragment);
                    		mLastTab.fragment = mLastTab.firstFragment;
                    	}
                	} else {
                		int size = mLastTab.mFragmentStack.size();
                		if (size > 0) {
                			Fragment f = mLastTab.mFragmentStack.get(size - 1);
                			ft.detach(f);
                		} else {
                			ft.detach(mLastTab.fragment);
                		}
                	}
                }
            }
            if (newTab != null) {
                if (newTab.fragment == null) {
                    newTab.firstFragment = Fragment.instantiate(mActivity,
                            newTab.clss.getName(), newTab.args);
                    ((TabFragment)newTab.firstFragment).setTabFragmentActivity((TabFragmentActivity)mActivity);
                    newTab.fragment = newTab.firstFragment;
                    ft.add(mContainerId, newTab.fragment, newTab.tag);
                } else {
                	setTabFragment(newTab,ft);
                    //ft.attach(newTab.firstFragment);
                }
            }

            mLastTab = newTab;
            ft.commit();
            mActivity.getSupportFragmentManager().executePendingTransactions();
        }
    }
}
